package com.engine.salary.formlua.func.date;

import com.alibaba.fastjson.JSONObject;
import com.engine.salary.formlua.entity.parameter.DataType;
import com.engine.salary.formlua.entity.parameter.DateAndString;
import com.engine.salary.formlua.entity.parameter.FuncNames;
import com.engine.salary.formlua.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @className：
 * @Description：日期Excel函数,函数传递参数支持JSON或者直接传入所需的String值， 函数自动判断参数类型，String类型可以直接当作日期字符串使用，如果是JSON，则转成JSON对象后获取content值
 * @Author：
 * @date：
 */
public class DateTimeServiceImpl implements DateTimeService {
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private String format = "yyyy-MM-dd HH:mm:ss";
    private Calendar calendar = Calendar.getInstance();

//    private RemoteAttendService remoteAttendService;
//    private RemoteAttend4FormService remoteAttend4FormService;
//    private TenantHttpInvokerService tenantHttpInvokerService;

    /**
     * 返回当前日期时间
     *
     * @return
     */
    @Override
    public DataType now(Object... objects) {
        int number = IgnoreParamFilter.getSetFuncNumber(FuncNames.NOW.toString());
        if (objects.length > 0) {
            return new DataType(DataType.STRING, "");
        }
        formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowStr = formatter.format(new Date());
        return new DataType(DataType.STRING, nowStr);
    }

    /**
     * 返回当前日期
     *
     * @return
     */
    @Override
    public DataType today(Object... objects) {
        int number = IgnoreParamFilter.getSetFuncNumber(FuncNames.TODAY.toString());
        if (objects.length > 0) {
            return new DataType(DataType.STRING, "");
        }
        formatter = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = formatter.format(new Date());
        return new DataType(DataType.STRING, dateStr);
    }

    /**
     * 格式化时间日期
     *
     * @param objects
     * @return
     */
    @Override
    public DataType dateFormat(Object... objects) {
        Class[] typeObjects = new Class[]{DateAndString.class, String.class};
        String func = "DATEFORMAT";
        IgnoreParamFilter.commonFilter(func, 2, 2, typeObjects, objects);
        Object result = objects[0];
        String dateStr = "";
        Object p1 = objects[0];
        Object p2 = objects[1];
        if (ExcelParamUtil.checkIsNull(p1, p2)) {
            throw new RuntimeException("日期格式化函数参数不能为空");
        }
        if (p1 instanceof DataType) {
            DataType dataType = (DataType) p1;
            dateStr = ExcelParamUtil.getParamContent(dataType.getContent(), "date") != null ? ExcelParamUtil.getParamContent(dataType.getContent(), "date").toString() : "";
        } else {
            if (p1 instanceof Date) {
                dateStr = formatter.format(p1);
            } else {
                dateStr = p1.toString();
            }
        }
        String formatStr = (ExcelParamUtil.getParamContent(p2, "string") != null ? ExcelParamUtil.getParamContent(p2, "string") : "").toString().replaceAll("D", "d");
        try {
            String formatterStr = DateUtil.buildFormat(dateStr);
            formatter = new SimpleDateFormat(formatterStr);
            Date sourceDate = formatter.parse(dateStr);
            formatter = new SimpleDateFormat(formatStr);
            dateStr = formatter.format(sourceDate);
            result = dateStr;
        } catch (ParseException e) {
            logger.error("err", e);
            return new DataType(DataType.STRING, "");
        }

        return new DataType(DataType.STRING, result);
    }

    /**
     * 两个日期加减
     *
     * @param
     * @param
     * @return
     */
    @Override
    public DataType dateDiff(Object... objects) {
        Class[] typeObjects = new Class[]{DateAndString.class, DateAndString.class, String.class};
        IgnoreParamFilter.commonFilter("DATEDIFF", 2, 3, typeObjects, objects);
        Long secondsL = new Long(60 * 60 * 1000);//计算日期时间间距的单位，默认为小时

        Long nd = buildSecondsFmt("D");
        Long nh = buildSecondsFmt("H");
        Long nm = buildSecondsFmt("I");
        Long ns = buildSecondsFmt("S");


        Double result = new Double(0);
        String type = "D";
        String sContent = DateUtil.getContent(objects[0], formatter);
        String eContent = DateUtil.getContent(objects[1], formatter);
        if (ExcelParamUtil.checkIsNull(sContent, eContent, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        Date startDate = null;
        Date endDate = null;

        format = DateUtil.buildFormat(sContent);
        startDate = formateDateStr(sContent, format);
        format = DateUtil.buildFormat(eContent);
        endDate = formateDateStr(eContent, format);
        if (startDate == null || endDate == null) {
            return new DataType(DataType.NUMBER, 0);
        }
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(startDate);
        //当前时间
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(endDate);


        long diff = cal2.getTime().getTime() - cal1.getTime().getTime();

        if (objects.length == 3) {
            type = ExcelParamUtil.getParamContent(objects[2], "string") != null ? ExcelParamUtil.getParamContent(objects[2], "string").toString() : "";
            secondsL = buildSecondsFmt(type);
        }
        Double time = new Double(0);
        boolean checkType = true;
        switch (type) {
            case "Y":
                time = DateTimeServiceImpl.getTime(startDate, endDate) / (nd.doubleValue()) / 365.0;
                break;
            case "M":
                Long monthR = DateTimeServiceImpl.getByField(cal1, cal2, Calendar.YEAR) * 12 + DateTimeServiceImpl.getByField(cal1, cal2, Calendar.MONTH);
                time = monthR.doubleValue();
                break;
            case "D":
                double dayR = DateTimeServiceImpl.getTime(startDate, endDate) / (nd.doubleValue());
                time = dayR;
                break;
            case "H":
                double hourH = DateTimeServiceImpl.getTime(startDate, endDate) / (nh.doubleValue());
                time = hourH;
                break;
            case "I":
                double minuR = DateTimeServiceImpl.getTime(startDate, endDate) / (nm.doubleValue());
                time = minuR;
                break;
            case "S":
                double seconR = DateTimeServiceImpl.getTime(startDate, endDate) / ns.doubleValue();
                time = seconR;
                break;
            default:
                checkType = false;
                break;
        }
        if (!checkType) {
            return new DataType(DataType.STRING, "");
        }
        BigDecimal b = new BigDecimal(time);
        double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        result = f1;
        return new DataType(DataType.NUMBER, result);
    }

    /**
     * 日期加减天数
     *
     * @param objects
     * @return
     */
    @Override
    public DataType dateAdd(Object... objects) {
        Class[] typeObjects = new Class[]{DateAndString.class, Integer.class, String.class};
        IgnoreParamFilter.commonFilter("DATEADD", 2, 3, typeObjects, objects);

        String type = "D";
        if (objects.length == 3) {
            type = objects[2].toString();
        }

        Object tcontent = DateUtil.getContent(objects[0], formatter);
        Double numD = Double.parseDouble(ExcelParamUtil.getParamContent(objects[1], "") != null ? ExcelParamUtil.getParamContent(objects[1], "").toString() : "");

        int num = numD.intValue();
        if (ExcelParamUtil.checkIsNull(tcontent, numD, type, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.STRING, "");
        }
        Object result = "";

        try {
            Date date = null;
            if (tcontent instanceof String || tcontent instanceof Character) {
                format = DateUtil.buildFormat(tcontent.toString());
                if (null == format) {
                    return new DataType(DataType.STRING, "");
                }
                date = formateDateStr(tcontent.toString(), format);
            } else {
                date = (Date) tcontent;
            }
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            boolean checkType = true;
            switch (type) {
                case "Y":
                    cal.add(Calendar.YEAR, num);
                    break;
                case "M":
                    cal.add(Calendar.MONTH, num);
                    break;
                case "D":
                    cal.add(Calendar.DAY_OF_MONTH, num);
                    break;
                case "H":
                    cal.add(Calendar.HOUR_OF_DAY, num);
                    break;
                case "I":
                    cal.add(Calendar.MINUTE, num);
                    break;
                case "S":
                    cal.add(Calendar.SECOND, num);
                    break;
                default:
                    checkType = false;
                    break;
            }
            if (!checkType) {
                String func = "DATEADD";
                return new DataType(DataType.STRING, "");
            }
            Date newDate = cal.getTime();
            String nDate = formateDateStr(newDate, format);
            result = nDate;

        } catch (ParseException e) {
            logger.error("err", e);
        }
        return new DataType(DataType.STRING, result);
    }

    /**
     * 返回年份
     *
     * @param objects
     * @return
     */
    @Override
    public DataType year(Object... objects) {
        Object reuslt = new Object();
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("YEAR", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        int year = 0;
        try {
            year = getDateTimeValue(date, "Y", "YEAR");
            reuslt = year;
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }

        return new DataType(DataType.NUMBER, reuslt);
    }

    /**
     * 返回是今年第几月
     *
     * @param objects
     * @return
     */
    @Override
    public DataType month(Object... objects) {

        Object reuslt = new Object();
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("MONTH", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        boolean isDate = checkDateString(date != null ? date.toString() : "");
        if (!isDate) {
            return new DataType(DataType.NUMBER, 0);
        }
        int month = 0;
        try {
            month = getDateTimeValue(date, "M", "MONTH");
            reuslt = month + 1;
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }

        return new DataType(DataType.NUMBER, reuslt);

    }

    /**
     * 返回日期是本月几号
     *
     * @param objects
     * @return
     */
    @Override
    public DataType day(Object... objects) {
        Object reuslt = new Object();
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("DAY", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        int day = 0;
        try {
            day = getDateTimeValue(date, "D", "DAY");
            reuslt = day;
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }

        return new DataType(DataType.NUMBER, reuslt);

    }

    /**
     * 返回时钟位置
     *
     * @param objects
     * @return
     */
    @Override
    public DataType hour(Object... objects) {

        Object reuslt = new Object();
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("HOUR", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        Integer hour = 0;
        try {
            hour = getDateTimeValue(date, "H", "HOUR");
            reuslt = hour;
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }

        return new DataType(DataType.NUMBER, reuslt);

    }

    /**
     * 返回分钟位置
     *
     * @param objects
     * @return
     */
    @Override
    public DataType minute(Object... objects) {
        Object reuslt = new Object();
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("MINUTE", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        int minute = 0;
        try {
            minute = getDateTimeValue(date, "I", "MINUTE");

            reuslt = minute;
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }

        return new DataType(DataType.NUMBER, reuslt);
    }

    /***
     * 返回秒钟位置
     * @param objects
     * @return
     */
    @Override
    public DataType seconds(Object... objects) {
        Object reuslt = new Object();
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("SECOND", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        int seconds = 0;
        try {
            seconds = getDateTimeValue(date, "S", "SECOND");
            reuslt = seconds;
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }

        return new DataType(DataType.NUMBER, reuslt);

    }

    /**
     * 计算是本月的第几周
     *
     * @param objects
     * @return
     */
    @Override
    public DataType weekNum(Object... objects) {
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("WEEKNUM", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        int weekNum = 0;
        try {
            weekNum = getDateTimeValue(date, "WM", "WEEKNUM");
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }
        return new DataType(DataType.NUMBER, weekNum);
    }

    /**
     * 判断是周几，因为周几是从周天的0开始算，所以返回数据需要减1
     *
     * @param objects
     * @return
     */
    @Override
    public DataType weekDay(Object... objects) {
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("WEEKDAY", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        int weekDay = 0;
        try {
            weekDay = getDateTimeValue(date, "DW", "WEEKDAY");
        } catch (ParseException e) {
            logger.error("err", e);
        }
        return new DataType(DataType.NUMBER, weekDay > 0 ? (weekDay - 1) : weekDay);
    }

    @Override
    public DataType dayOfMonth(Object... objects) {
        String dayType = "";
        if (objects != null && objects.length > 0 && objects[0] != null) {
            dayType = objects[0].toString();
        }

        // 获取当前年份、月份、日期
        Calendar cale = null;
        // 获取当月第一天和最后一天
        SimpleDateFormat formatTemp = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String firstday = "", lastday = "";
        String date = "";
        switch (dayType.toLowerCase()) {
            case "first":
                // 获取当前月的第一天
                cale = Calendar.getInstance();
                cale.add(Calendar.MONTH, 0);
                cale.set(Calendar.DAY_OF_MONTH, 1);
                cale.set(Calendar.HOUR_OF_DAY, 0);
                cale.set(Calendar.MINUTE, 0);
                firstday = formatTemp.format(cale.getTime());
                date = firstday;
                break;
            case "last":
                // 获取当前月的最后一天
                cale = Calendar.getInstance();
                cale.add(Calendar.MONTH, 1);
                cale.set(Calendar.DAY_OF_MONTH, 0);
                cale.set(Calendar.HOUR_OF_DAY, 0);
                cale.set(Calendar.MINUTE, 0);
                lastday = formatTemp.format(cale.getTime());
                date = lastday;
                break;
            default:
                // 获取指定的某一天
                if (dayType == null || dayType.trim().equalsIgnoreCase("")) {
                    dayType = "0";
                }
                cale = Calendar.getInstance();
                cale.add(Calendar.MONTH, 1);
                cale.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dayType));
                cale.set(Calendar.HOUR_OF_DAY, 0);
                cale.set(Calendar.MINUTE, 0);
                lastday = formatTemp.format(cale.getTime());
                date = lastday;
                break;
        }
        return new DataType(DataType.STRING, date);
    }

    @Override
    public DataType monthOfYear(Object... objects) {
        String dayType = "";
        if (objects != null && objects.length > 0 && objects[0] != null) {
            dayType = objects[0].toString();
        }
        if (dayType == null || dayType.equalsIgnoreCase("")) {
            dayType = "0";
        }
        int month = Integer.parseInt(dayType);
        if (month > 0) {
            month -= 1;
        }
        SimpleDateFormat formatTemp = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Calendar cale = Calendar.getInstance();
        cale.set(cale.get(Calendar.YEAR), month, 1);

        String lastday = formatTemp.format(cale.getTime());
        System.out.println(lastday);
        return new DataType(DataType.STRING, lastday);
    }

    @Override
    public DataType timeOfDay(Object... objects) {
        String dayType = "";
        if (objects != null && objects.length > 0 && objects[0] != null) {
            dayType = objects[0].toString();
        }
        SimpleDateFormat dayFormatTemp = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat formatTemp = new SimpleDateFormat("HH:mm");
        Calendar cale = Calendar.getInstance();
        try {
            cale.setTime(new Date());
        } catch (Exception e) {
            logger.error("err", e);
        }
        cale.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dayType));
        cale.set(Calendar.MINUTE, 0);
        String lastday = formatTemp.format(cale.getTime());
        return new DataType(DataType.STRING, lastday);
    }

    @Override
    public DataType eoMonth(Object... objects) {
        Object result = "";
        //校验
        Class[] typeObjects = new Class[]{DateAndString.class, Integer.class};
        IgnoreParamFilter.commonFilter("EOMONTH", 1, 2, typeObjects, objects);

        //获取日期和加减参数
        Object dateObj = objects[0];
        Object dateContent = dateObj != null ? DateUtil.getContent(dateObj, formatter) : null;

        Object tempObj = objects.length > 1 ? objects[1] : null;
        Object numObj = tempObj != null && ExcelParamUtil.getParamContent(tempObj, "") != null ? ExcelParamUtil.getParamContent(tempObj, "").toString() : null;

        int num = numObj != null ? Integer.parseInt(numObj + "") : 0;
        if (ExcelParamUtil.checkIsNull(dateContent, ExcelParamUtil.CHECKLEVEL_STRING)) {
            throw new RuntimeException("日期参数不能为空");
        }

        try {
            Date date = null;
            if (dateContent instanceof String || dateContent instanceof Character) {
                format = DateUtil.buildFormat(dateContent.toString());
                if (null == format) {
                    return null;
                }
                date = formateDateStr(dateContent.toString(), format);
            } else {
                date = (Date) dateContent;
            }

            //在传入日期上进行月份加减操作，并设置为当月第一天
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(Calendar.MONTH, num);
            cal.set(Calendar.DAY_OF_MONTH, 1);

            //取该月最后一天
            cal.add(Calendar.MONTH, 1);
            cal.add(Calendar.DAY_OF_MONTH, -1);

            Date newDate = cal.getTime();
            result = formateDateStr(newDate, format);
        } catch (ParseException e) {
            logger.error("eoMonth执行出错:" + e.getMessage(), e);
        }
        return new DataType(DataType.STRING, result);
    }

//    @Override
//    public DataType workdayIntl(Object... objects) {
//        //校验
//        Object result = null;
//        IgnoreParamFilter.commonFilter("NETWORKDAYSPI", 3, 3, null, objects);
//
//        //获取开始日期
//        Object startObj = objects[0];
//        Object startDateObj = startObj != null ? DateUtil.getContent(startObj, formatter) : null;
//
//        Date startDate = null;
//        if (startDateObj != null) {
//
//            if (startDateObj instanceof String || startDateObj instanceof Character) {
//                format = DateUtil.buildFormat(startDateObj.toString());
//                if (null == format) {
//                    logger.error("workdayIntl函数执行时,开始时间获取format为空，已返回null");
//                    return null;
//                }
//                startDate = formateDateStr(startDateObj.toString(), format);
//            } else {
//                startDate = (Date) startDateObj;
//            }
//        }
//
//        //结束日期
//        Object endObj = objects[1];
//        Object endDateObj = endObj != null ? DateUtil.getContent(endObj, formatter) : null;
//
//        Date endDate = null;
//        if (endDateObj != null) {
//
//            if (endDateObj instanceof String || endDateObj instanceof Character) {
//                format = DateUtil.buildFormat(endDateObj.toString());
//                if (null == format) {
//                    logger.error("workdayIntl函数执行时,结束时间获取format为空，已返回null");
//                    return null;
//                }
//                endDate = formateDateStr(endDateObj.toString(), format);
//            } else {
//                endDate = (Date) endDateObj;
//            }
//        }
//
//        //人员参数
//        Object employeeObj = objects[2];
//        String empIdStr = employeeObj != null ? ((DataType) employeeObj).getContent() + "" : null;
//
//        DataCollectionEmployee currEmp = employeeObj != null ? ((DataType) employeeObj).getEmployee() : null;
//        String tenantKey = currEmp != null ? currEmp.getTenantKey() : null;
//
//        if (ExcelParamUtil.checkIsNull(startDate, endDate, empIdStr, ExcelParamUtil.CHECKLEVEL_STRING)) {
//            throw new RuntimeException("NETWORKDAYSPI函数参数不能为空");
//        }
//
//        if (StringUtils.isEmpty(tenantKey)) {
//            logger.error("workdayIntl函数执行时,tenantKey,已返回null");
//            return null;
//        }
//
//        //结果是否取相反数
//        boolean isOpposite = false;
//        Date begin = startDate;
//        Date end = endDate;
//
//        if (startDate.after(end)) {
//            isOpposite = true;
//            begin = endDate;
//            end = startDate;
//        }
//
//        //结束时间临界值为昨天23:59:59
//        Date yesterdayEnd = new Date();
//        yesterdayEnd = DateUtils.addDays(yesterdayEnd, -1);
//        yesterdayEnd = com.weaver.teams.util.DateUtils.setTimeToEndOfDay(yesterdayEnd);
//
//        //最小时间大于昨天最后一刻，则计算结果为0
//        if (begin.after(yesterdayEnd)) {
//            return new DataType(DataType.NUMBER, 0);
//        }
//        //最大日期大于昨天最后一刻，另结束时间等于昨天最后一刻
//        if (end.after(yesterdayEnd)) {
//            end = yesterdayEnd;
//        }
//
//        //间隔天数
//        int workDays = 0;
//        //是否购买了考勤模块
//        boolean attendPay = tenantHttpInvokerService.isPayModule(tenantKey, TenantModuleType.attend);
//
//        if (attendPay) {
//            //按考勤规则设置来
//            Long empId = Long.parseLong(empIdStr);
//            Map<Long, Map<String, AttendDayType>> tempMap = null;
//
//            try {
//                WeaverSentinelContext.setDowngradeType(false);
//                tempMap = remoteAttendService.queryDayType(Lists.newArrayList(empId), begin, end, tenantKey);
//            } catch (Exception e) {
//                if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) {
//                    //降级逻辑编写
//                    logger.info("******workdayIntl的remoteAttendService.queryDayType走了weaver-common-excel-formula中的降级******");
//                    return new DataType(DataType.NUMBER, 0);
//                } else {
//                    logger.error("workdayIntl的remoteAttendService.queryDayType查询出错:" + e.getMessage());
//                }
//            }
//
//            if (MapUtils.isNotEmpty(tempMap)) {
//                Map<String, AttendDayType> dayTypeMap = tempMap.get(empId);
//                if (MapUtils.isEmpty(dayTypeMap)) {
//                    dayTypeMap = Maps.newHashMap();
//                }
//
//                Date attendDate = null;
//                AttendDayType dayType = null;
//                int days = DateUtil.daysBetween(begin, end);
//
//                //计算工作日天数
//                for (int i = 0; i <= days; i++) {
//                    attendDate = DateUtils.addDays(begin, i);
//                    String dayStr = DateFormatUtils.format(attendDate, "yyyy-MM-dd");
//
//                    dayType = dayTypeMap.get(dayStr);
//                    if (dayType != null && dayType == AttendDayType.WORK) {
//                        workDays++;
//                    }
//                }
//            }
//        } else {
//            //按法定节假日算
//            List<String> tempHolidays = Lists.newArrayList();
//            List<Attend4FormDay> holidays = null;
//
//            try {
//                WeaverSentinelContext.setDowngradeType(false);
//                holidays = remoteAttend4FormService.queryDefaultHoliday(begin, end);
//            } catch (Exception e) {
//                if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) {
//                    //降级逻辑编写
//                    logger.info("******workdayIntl的remoteAttend4FormService.queryDefaultHoliday走了weaver-common-excel-formula中的降级******");
//                    return new DataType(DataType.NUMBER, 0);
//                } else {
//                    logger.error("workdayIntl的remoteAttend4FormService.queryDefaultHoliday查询出错:" + e.getMessage());
//                }
//            }
//
//            if (CollectionUtils.isNotEmpty(holidays)) {
//                for (Attend4FormDay tempDay : holidays) {
//                    String dayStr = DateFormatUtils.format(tempDay.getDay(), "yyyy-MM-dd");
//                    tempHolidays.add(dayStr);
//                }
//            }
//
//            Date attendDate = null;
//            Calendar cal = Calendar.getInstance();
//            int days = DateUtil.daysBetween(begin, end);
//
//            //计算工作日天数
//            for (int i = 0; i <= days; i++) {
//                attendDate = DateUtils.addDays(begin, i);
//                String dayStr = DateFormatUtils.format(attendDate, "yyyy-MM-dd");
//
//                //节假日
//                if (tempHolidays.contains(dayStr)) {
//                    continue;
//                }
//
//                //周末
//                cal.setTime(attendDate);
//                if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
//                    continue;
//                }
//
//                //工作日
//                workDays++;
//            }
//        }
//        if (isOpposite) {
//            workDays = workDays * (-1);
//        }
//
//        logger.info("workdayIntl计算结果:" + workDays);
//        return new DataType(DataType.NUMBER, workDays);
//
//    }

    @Override
    public DataType maxDate(Object... objects) {
        Object dateObj = null;
        Date date = null;
        Date maxDate = null;

        //取最大日期
        for (int i = 0; i < objects.length; i++) {
            dateObj = objects[i];
            if (dateObj == null) continue;

            //如果类型是DataType
            if (dateObj instanceof DataType) {
                DataType dataType = (DataType) dateObj;
                dateObj = dataType.getContent();
            }
            if (dateObj == null) continue;

            //字符串或Date强转
            if (dateObj instanceof String || dateObj instanceof Character) {
                String format = DateUtil.buildFormat(dateObj.toString());
                if (StringUtils.isNotEmpty(format)) date = formateDateStr(dateObj.toString(), format);
            } else {
                date = (Date) dateObj;
            }

            if (date != null && (maxDate == null || date.after(maxDate))) maxDate = date;
        }

        //日期格式化
        String rtnStr = maxDate != null ? DateFormatUtils.format(maxDate, "yyyy-MM-dd") : "";
        return new DataType(DataType.STRING, rtnStr);
    }

    @Override
    public DataType minDate(Object... objects) {
        Object dateObj = null;
        Date date = null;
        Date minDate = null;

        //取最小日期
        for (int i = 0; i < objects.length; i++) {
            dateObj = objects[i];
            if (dateObj == null) continue;

            //如果类型是DataType
            if (dateObj instanceof DataType) {
                DataType dataType = (DataType) dateObj;
                dateObj = dataType.getContent();
            }
            if (dateObj == null) continue;

            if (dateObj instanceof String || dateObj instanceof Character) {
                String format = DateUtil.buildFormat(dateObj.toString());
                if (StringUtils.isNotEmpty(format)) date = formateDateStr(dateObj.toString(), format);
            } else {
                date = (Date) dateObj;
            }

            if (date != null && (minDate == null || date.before(minDate))) minDate = date;
        }

        //日期格式化
        String rtnStr = minDate != null ? DateFormatUtils.format(minDate, "yyyy-MM-dd") : "";
        return new DataType(DataType.STRING, rtnStr);
    }

    @Override
    public DataType compareDate(Object... objects) {
        Date first = null;
        Date second = null;
        Object paramObj = objects[0];
        Object paramObjSecond = objects[1];
        if (paramObj instanceof DataType) {
            DataType dataType = (DataType) paramObj;
            if (dataType.getContent() != null && StringUtils.isNotEmpty(dataType.getContent() + "")) {
                boolean isDate = DateUtil.isDateComponent(paramObj);
                if (isDate) {
                    first = DateUtil.buildDateByDateChar(dataType.getContent() + "");
                }
            }
        } else {
            first = DateUtil.buildDateByDateChar(paramObj + "");
        }

        if (paramObjSecond instanceof DataType) {
            DataType dataType = (DataType) paramObjSecond;
            if (dataType.getContent() != null && StringUtils.isNotEmpty(dataType.getContent() + "")) {
                boolean isDate = DateUtil.isDateComponent(paramObjSecond);
                if (isDate) {
                    second = DateUtil.buildDateByDateChar(dataType.getContent() + "");
                }
            }
        } else {
            second = DateUtil.buildDateByDateChar(paramObjSecond + "");
        }

        if (first == null || second == null) {
            return new DataType(DataType.BOOL, false);
        }

        if (first.getTime() - second.getTime() != 0) {
            return new DataType(DataType.BOOL, false);
        } else {
            return new DataType(DataType.BOOL, true);
        }
    }

    @Override
    public DataType currYear(Object... objects) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int year = cal.get(Calendar.YEAR);
        return new DataType(DataType.NUMBER, year);
    }

    @Override
    public DataType currMonth(Object... objects) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int year = cal.get(Calendar.MONTH) + 1;
        return new DataType(DataType.NUMBER, year);
    }

    @Override
    public DataType currDay(Object... objects) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int year = cal.get(Calendar.DAY_OF_MONTH);
        return new DataType(DataType.NUMBER, year);
    }

    @Override
    public DataType currWeek(Object... objects) {
        int weekDay = 0;
        try {
            weekDay = getDateTimeValue(new Date(), "DW", "WEEKDAY");
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }
        return new DataType(DataType.NUMBER, weekDay > 0 ? (weekDay - 1) : weekDay);
    }

    @Override
    public DataType currHour(Object... objects) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int year = cal.get(Calendar.HOUR_OF_DAY);
        return new DataType(DataType.NUMBER, year);
    }

    @Override
    public DataType currMinute(Object... objects) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int year = cal.get(Calendar.MINUTE);
        return new DataType(DataType.NUMBER, year);
    }

    @Override
    public DataType currSecond(Object... objects) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int year = cal.get(Calendar.SECOND);
        return new DataType(DataType.NUMBER, year);
    }

    @Override
    public DataType daysInMonth(Object... objects) {
        Class[] typeObjects = new Class[]{DateAndString.class};
        IgnoreParamFilter.commonFilter("YEAR", 1, 1, typeObjects, objects);
        Object obj = objects[0];
        Object date = DateUtil.getContent(obj, formatter);
        if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) {
            return new DataType(DataType.NUMBER, 0);
        }
        int year = 0;
        try {
            year = getDateTimeValue(date, "Y", "YEAR");
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }

        IgnoreParamFilter.commonFilter("MONTH", 1, 1, typeObjects, objects);
        int month = 0;
        try {
            month = getDateTimeValue(date, "M", "MONTH") + 1;
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }

        YearMonth yearMonth = YearMonth.of(year, month);
        int daysInMonth = yearMonth.lengthOfMonth();
        return new DataType(DataType.NUMBER, daysInMonth);
    }
    /*******以下为日期函数的一些公共逻辑********/


    /**
     * 获取日期时间的单位值，指定类型为Type，默认为 'D' 天数
     *
     * @param date
     * @param type
     * @return
     * @throws ParseException
     */
    public Integer getDateTimeValue(Object date, String type, String func) throws ParseException {
        int result = 0;
        try {
            boolean isTime = false;
            Date fDate = null;
            if (date instanceof String) {
                boolean isDate = checkDateString(date != null ? date.toString() : "");
                if (!isDate) {
                    return 0;
                }
                format = DateUtil.buildFormat(date.toString(), type);
                if (format == null) {
                    format = DateUtil.buildFormat(date.toString());
                }
                fDate = formateDateStr(date.toString(), format);
                if (date.toString().indexOf(":") > 0 && date.toString().indexOf("-") < 0) {
                    isTime = true;
                    if (!type.equals("H") && !type.equals("I") && !type.equals("S")) {
                        Integer number = IgnoreParamFilter.getSetFuncNumber(func);
                        JSONObject errorJson = ErrorUtil.buildError(func, number, number, func + "函数参数错误");
                        throw new RuntimeException(errorJson.getString("msg"));
                    }
                }
            } else {
                fDate = (Date) date;
            }

            int calendarType = 0;
            switch (type) {
                case "Y":
                    calendarType = Calendar.YEAR;
                    break;
                case "M":
                    calendarType = Calendar.MONTH;
                    break;
                case "D":
                    calendarType = Calendar.DAY_OF_MONTH;
                    break;
                case "H":
                    if (isTime) {
                        return Integer.parseInt(date.toString().split(":")[0]);
                    }
                    calendarType = Calendar.HOUR_OF_DAY;
                    break;
                case "I":
                    if (isTime) {
                        return Integer.parseInt(date.toString().split(":")[1]);
                    }
                    calendarType = Calendar.MINUTE;
                    break;
                case "S":
                    if (isTime) {
                        return Integer.parseInt(date.toString().split(":")[2]);
                    }
                    calendarType = Calendar.SECOND;
                    break;
                case "WM":
                    calendarType = Calendar.WEEK_OF_YEAR;
                    long startTime1 = fDate.getTime();
                    Calendar calendar = Calendar.getInstance();
                    calendar.setFirstDayOfWeek(Calendar.SUNDAY);//设置星期一为一周开始的第一天
                    calendar.setMinimalDaysInFirstWeek(4);//可以不用设置
                    calendar.setTimeInMillis(startTime1);//获得当前的时间戳
                    int weekOfYear = calendar.get(calendarType);//获得当前日期属于今年的第几周
                    result = weekOfYear;
                    logger.info("当前是第" + result + "周");
                    return result;
                case "DW":
                    calendarType = Calendar.DAY_OF_WEEK;
                    break;
                default:
                    calendarType = Calendar.HOUR_OF_DAY;
                    break;
            }
            calendar.setTime(fDate);
            result = calendar.get(calendarType);
        } catch (RuntimeException e) {
            logger.error("err", e);
            result = 0;
        }
        return result;
    }

    /**
     * 格式化日期时间
     *
     * @param dateStr 日期时间原字符串
     * @param format  格式
     * @return
     * @throws ParseException
     */
    private Date formateDateStr(String dateStr, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date ndate = null;
        try {
            ndate = sdf.parse(dateStr);
        } catch (ParseException e) {
            logger.error("err", e);
            throw new RuntimeException(e);
        }
        return ndate;
    }

    /**
     * 格式日期时间为字符串
     *
     * @param date
     * @param format
     * @return
     * @throws ParseException
     */
    private String formateDateStr(Date date, String format) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        String ndate = sdf.format(date);
        return ndate;
    }


    /**
     * 判断时间间距的单位类型
     *
     * @param type
     * @return
     */
    private Long buildSecondsFmt(String type) {
        Long secondsL = null;
        switch (type) {
            case "Y":
                secondsL = (long) (365 * 24 * 60 * 60 * 1000);
                break;
            case "M":
                secondsL = (long) (30 * 24 * 60 * 60 * 1000);
                break;
            case "D":
                secondsL = (long) (24 * 60 * 60 * 1000);
                break;
            case "H":
                secondsL = (long) (60 * 60 * 1000);
                break;
            case "I":
                secondsL = (long) (60 * 1000);
                break;
            case "S":
                secondsL = 1000L;
                break;
            default:
                secondsL = (long) (60 * 60 * 1000);
                break;
        }
        return secondsL;
    }

    static Calendar calendar2 = Calendar.getInstance();
    public static SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    static String format2 = "yyyy-MM-dd HH:mm:ss";


    public static Integer getDateTimeValue2(Object date, String type, String func) throws ParseException {
        int result = 0;
        boolean isTime = false;
        Date fDate = null;
        if (date instanceof String) {
            format2 = DateUtil.buildFormat(date.toString());
            fDate = formateDateStr2(date.toString(), format2);
            if (date.toString().indexOf(":") > 0 && !date.toString().contains("-")) {
                isTime = true;
                if (!type.equals("H") && !type.equals("I") && !type.equals("S")) {
                    Integer number = IgnoreParamFilter.getSetFuncNumber(func);
                    JSONObject errorJson = ErrorUtil.buildError(func, number, number, func + "函数参数错误");
                    throw new RuntimeException(errorJson.getString("msg"));
                }
            }
        } else {
            fDate = (Date) date;
        }

        int calendarType = 0;
        switch (type) {
            case "Y":
                calendarType = Calendar.YEAR;
                break;
            case "M":
                calendarType = Calendar.MONTH;
                break;
            case "D":
                calendarType = Calendar.DAY_OF_MONTH;
                break;
            case "H":
                if (isTime) {
                    return Integer.parseInt(date.toString().split(":")[0]);
                }
                calendarType = Calendar.HOUR_OF_DAY;
                break;
            case "I":
                if (isTime) {
                    return Integer.parseInt(date.toString().split(":")[1]);
                }
                calendarType = Calendar.MINUTE;
                break;
            case "S":
                if (isTime) {
                    return Integer.parseInt(date.toString().split(":")[2]);
                }
                calendarType = Calendar.SECOND;
                break;
            case "WM":
                calendarType = Calendar.WEEK_OF_MONTH;
                break;
            case "DW":
                calendarType = Calendar.DAY_OF_WEEK;
                break;
            default:
                calendarType = Calendar.HOUR_OF_DAY;
                break;
        }
        calendar2.setTime(fDate);
        result = calendar2.get(calendarType);
        return result;
    }

    private static Date formateDateStr2(String dateStr, String format) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date ndate = null;
        ndate = sdf.parse(dateStr);
        return ndate;
    }

    private boolean checkDateString(String dateString) {
        List<String> datafList = new ArrayList<String>();
        datafList.add("yyyyMMddHHmmss");
        datafList.add("yyyyMMdd");
        datafList.add("yyyyMMddHHmm");
        datafList.add("HH:mm");
        datafList.add("HH:mm:ss");
        if (RegularUtil.isNumber(dateString)) {
            return false;
        }
        boolean r = false;
        for (String s : datafList) {
            SimpleDateFormat sdf = new SimpleDateFormat(s);

            Date ndate = null;
            try {
                ndate = sdf.parse(dateString);
                r = true;
                break;
            } catch (ParseException e) {
                logger.error(e.getMessage());
                r = false;
            }
        }
        if (r) {
            if (RegularUtil.isNumber(dateString)) {
                r = false;
            }
        }
        return r;
    }


    public static double getBetween(String beginTime, String endTime, String returnPattern) throws ParseException {

        String format = DateUtil.buildFormat(beginTime);
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date beginDate = sdf.parse(beginTime);

        format = DateUtil.buildFormat(endTime);
        sdf = new SimpleDateFormat(format);
        Date endDate = sdf.parse(endTime);

        Calendar beginCalendar = Calendar.getInstance();
        Calendar endCalendar = Calendar.getInstance();
        beginCalendar.setTime(beginDate);
        endCalendar.setTime(endDate);

        double resutl;
        switch (returnPattern) {
            case "Y":
                resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / (24 * 60 * 60 * 1000) / 365.0;
                break;
            case "M":
                resutl = DateTimeServiceImpl.getByField(beginCalendar, endCalendar, Calendar.YEAR) * 12 + DateTimeServiceImpl.getByField(beginCalendar, endCalendar, Calendar.MONTH);
                break;
            case "D":
                resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / (24 * 60 * 60 * 1000);
                break;
            case "H":
                Long nd = new Long(60 * 60 * 1000);
                resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / (nd.doubleValue());
                break;
            case "I":
                resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / (60 * 1000);
                break;
            case "S":
                resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / 1000;
                break;
            default:
                resutl = 0L;
                break;
        }
        return resutl;
    }


    private static Long getByField(Calendar beginCalendar, Calendar endCalendar, int calendarField) {
        int r = endCalendar.get(calendarField) - beginCalendar.get(calendarField);
        return (long) r;
    }

    private static long getTime(Date beginDate, Date endDate) {
        return endDate.getTime() - beginDate.getTime();
    }

//	public static void main(String[] args) {
//		try {
//			logger.info(DateTimeServiceImpl.getBetween("2017-05-02 22:00:00", "2016-10-02 23:15:00", "Y"));
//		} catch (ParseException e) {
//			logger.error("err",e);
//		}
//
//	}
}
